#ifndef __M_QUEUE_H__
#define __M_QUEUE_H__

// 引入自定义工具、日志、Protobuf 消息头文件
#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"

// 标准库头文件
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>

namespace zdfmq
{

    // ====================== 消息队列核心结构体：MsgQueue ======================
    // 描述一条消息队列的元数据（名称、持久化等属性、参数）
    struct MsgQueue
    {
        // 智能指针类型别名，统一用 shared_ptr 管理对象生命周期
        using ptr = std::shared_ptr<MsgQueue>;

        // 队列核心属性
        std::string name; // 队列唯一名称
        bool durable;     // 是否持久化（重启后元数据是否保留）
        bool exclusive;   // 是否独占（通常用于临时队列，限制创建者使用）
        bool auto_delete; // 无消费者且消息消费完时，是否自动删除
        // Protobuf 类型的参数映射（存储自定义键值对，如扩展配置）
        google::protobuf::Map<std::string, std::string> args;

        // 无参构造（用于反序列化、默认初始化场景）
        MsgQueue() = default;

        // 带参构造（创建队列时直接初始化核心属性）
        MsgQueue(const std::string &qname,
                 bool qdurable,
                 bool qexclusive,
                 bool qauto_delete,
                 const google::protobuf::Map<std::string, std::string> &qargs)
            : name(qname),
              durable(qdurable),
              exclusive(qexclusive),
              auto_delete(qauto_delete),
              args(qargs)
        {
        }

        // 【参数反序列化】从格式化字符串解析参数到 args（用于数据库恢复队列元数据）
        void setArgs(const std::string &str_args)
        {
            std::vector<std::string> sub_args;
            // 按 & 分割字符串（如 "k1=v1&k2=v2" → 拆成 ["k1=v1", "k2=v2"]）
            StrHelper::split(str_args, "&", sub_args);
            for (auto &str : sub_args)
            {
                size_t pos = str.find("=");
                if (pos == std::string::npos)
                    continue; // 格式错误跳过
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args[key] = val; // 存入 Protobuf Map
            }
        }

        // 【参数序列化】将 args 转成格式化字符串（用于存入数据库）
        std::string getArgs()
        {
            std::string result;
            // 遍历 Protobuf Map，拼接成 "k1=v1&k2=v2&..." 格式
            for (auto start = args.begin(); start != args.end(); ++start)
            {
                result += start->first + "=" + start->second + "&";
            }
            return result;
        }
    };

    // ====================== 队列持久化映射器：MsgQueueMapper ======================
    // 负责操作 SQLite 数据库，实现队列元数据的【增删查】与【表管理】
    using QueueMap = std::unordered_map<std::string, MsgQueue::ptr>; // 内存队列映射类型
    class MsgQueueMapper
    {
    public:
        // 构造函数：初始化数据库连接，创建目录、打开数据库、确保表存在
        MsgQueueMapper(const std::string &dbfile)
            : _sql_helper(dbfile)
        {
            // 获取数据库文件所在目录并创建（避免目录不存在导致数据库打开失败）
            std::string path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);

            _sql_helper.open(); // 打开数据库连接
            createTable();      // 确保队列表存在
        }

        // 创建队列表（若不存在），字段：name(主键)、durable、exclusive、auto_delete、args
        void createTable()
        {
            std::stringstream sql;
            sql << "create table if not exists queue_table("
                << "name varchar(32) primary key, " // 队列名称，主键保证唯一
                << "durable int, "                  // 持久化标记（0/1 存 bool）
                << "exclusive int, "                // 独占标记（0/1 存 bool）
                << "auto_delete int, "              // 自动删除标记（0/1 存 bool）
                << "args varchar(128));";           // 参数字符串（key=val&...）
            // 断言确保建表 SQL 执行成功，失败则终止程序（调试阶段方便发现问题）
            assert(_sql_helper.exec(sql.str(), nullptr, nullptr));
        }

        // 删除队列表（测试/清理数据时用，生产环境谨慎调用）
        void removeTable()
        {
            std::string sql = "drop table if exists queue_table;";
            _sql_helper.exec(sql, nullptr, nullptr);
        }

        // 插入队列元数据到数据库（仅当队列持久化时调用）
        bool insert(MsgQueue::ptr &queue)
        {
            std::stringstream sql;
            sql << "insert into queue_table values("
                << "'" << queue->name << "', "      // 字符串字段用单引号包裹
                << (queue->durable ? 1 : 0) << ", " // bool 转 int 存入数据库
                << (queue->exclusive ? 1 : 0) << ", "
                << (queue->auto_delete ? 1 : 0) << ", "
                << "'" << queue->getArgs() << "');"; // 序列化后的参数字符串
            // 执行 SQL，返回是否成功
            return _sql_helper.exec(sql.str(), nullptr, nullptr);
        }

        // 从数据库删除指定队列（仅当队列持久化时调用）
        void remove(const std::string &name)
        {
            std::stringstream sql;
            sql << "delete from queue_table where name="
                << "'" << name << "';"; // 条件删除（按队列名称）
            _sql_helper.exec(sql.str(), nullptr, nullptr);
        }

        // 从数据库恢复所有队列元数据到内存（程序启动时加载历史队列）
        QueueMap recovery()
        {
            QueueMap result; // 存储恢复后的队列映射
            std::string sql = "select name, durable, exclusive, auto_delete, args from queue_table;";
            // 执行查询，用 selectCallback 处理结果集，将数据库行转成 MsgQueue 对象
            _sql_helper.exec(sql, selectCallback, &result);
            return result;
        }

    private:
        // 【结果集回调】数据库查询后，逐行解析为 MsgQueue 对象并插入内存映射
        static int selectCallback(void *arg, int numcol, char **row, char **fields)
        {
            // arg 是传入的 QueueMap 指针，用于存储恢复的队列
            QueueMap *result = (QueueMap *)arg;
            MsgQueue::ptr mqp = std::make_shared<MsgQueue>();

            // 按数据库查询结果的列顺序解析
            mqp->name = row[0];                         // 第 0 列：队列名称
            mqp->durable = (bool)std::stoi(row[1]);     // 第 1 列：durable（int 转 bool）
            mqp->exclusive = (bool)std::stoi(row[2]);   // 第 2 列：exclusive
            mqp->auto_delete = (bool)std::stoi(row[3]); // 第 3 列：auto_delete
            if (row[4])
            {                         // 第 4 列：参数字符串（可能为 NULL，需判断）
                mqp->setArgs(row[4]); // 反序列化为 Protobuf Map
            }

            // 使用 operator[] 插入元素
            (*result)[mqp->name] = mqp;

            // 或者使用 emplace 方法
            // result->emplace(mqp->name, mqp);

            return 0; // 回调返回 0 表示处理成功
        }

    private:
        SqliteHelper _sql_helper; // 封装的 SQLite 操作工具（简化数据库 API 调用）
    };

    // ====================== 队列内存管理器：MsgQueueManager ======================
    // 业务逻辑层，封装队列的【声明、删除、查询】等操作，保证线程安全，对接持久化
    class MsgQueueManager
    {
    public:
        // 智能指针类型别名，方便外部统一使用 shared_ptr
        using ptr = std::shared_ptr<MsgQueueManager>;

        // 构造函数：初始化持久化映射器，从数据库恢复队列到内存
        MsgQueueManager(const std::string &dbfile)
            : _mapper(dbfile)
        {
            _msg_queues = _mapper.recovery(); // 加载数据库中已有的队列元数据
        }

        // 【声明队列】支持幂等性（队列存在则直接返回 true），持久化队列会写入数据库
        bool declareQueue(const std::string &qname,
                          bool qdurable,
                          bool qexclusive,
                          bool qauto_delete,
                          const google::protobuf::Map<std::string, std::string> &qargs)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 加锁保证多线程安全
            auto it = _msg_queues.find(qname);
            if (it != _msg_queues.end())
            {
                return true; // 队列已存在，声明成功
            }

            // 队列不存在，创建新队列对象
            MsgQueue::ptr mqp = std::make_shared<MsgQueue>();
            mqp->name = qname;
            mqp->durable = qdurable;
            mqp->exclusive = qexclusive;
            mqp->auto_delete = qauto_delete;
            mqp->args = qargs; // 直接赋值 Protobuf Map

            // 持久化逻辑：若队列需要持久化，插入数据库
            if (qdurable)
            {
                bool ret = _mapper.insert(mqp);
                if (!ret)
                    return false; // 持久化失败则声明失败
            }

            // 存入内存映射，完成队列创建
            _msg_queues.insert(std::make_pair(qname, mqp));
            return true;
        }

        // 【删除队列】内存和数据库（若持久化）都删除，保证数据一致性
        void deleteQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 加锁保证线程安全
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
            {
                return; // 队列不存在，无需删除
            }

            // 持久化删除：若队列是持久化的，从数据库删除对应记录
            if (it->second->durable)
            {
                _mapper.remove(name);
            }

            // 内存中删除队列映射
            _msg_queues.erase(name);
        }

        // 【查询队列】返回智能指针，空指针表示队列不存在
        MsgQueue::ptr selectQueue(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 加锁保证线程安全
            auto it = _msg_queues.find(name);
            if (it == _msg_queues.end())
            {
                return MsgQueue::ptr(); // 返回空智能指针
            }
            return it->second;
        }

        // 获取内存中所有队列的映射（用于遍历、统计等场景）
        QueueMap allQueues()
        {
            std::unique_lock<std::mutex> lock(_mutex); // 加锁保证线程安全
            return _msg_queues;                        // 返回拷贝，避免外部直接修改内存数据
        }

        // 【检查队列存在性】
        bool exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 加锁保证线程安全
            return _msg_queues.count(name) > 0;
        }

        // 获取内存中队列的数量
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex); // 加锁保证线程安全
            return _msg_queues.size();
        }

        // 【清理所有队列】删除数据库表 + 清空内存（测试/重置环境时用）
        void clear()
        {
            _mapper.removeTable(); // 删除数据库表
            _msg_queues.clear();   // 清空内存映射
        }

    private:
        std::mutex _mutex;      // 互斥锁，保证多线程操作队列时的线程安全
        MsgQueueMapper _mapper; // 持久化操作器（对接 SQLite 数据库）
        QueueMap _msg_queues;   // 内存中存储的队列映射（名称为键，队列对象为值）
    };

} // namespace zdfmq

#endif